home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d3 / smooth.arc / SMOOTH.ASM < prev    next >
Assembly Source File  |  1991-01-10  |  41KB  |  828 lines

  1. ;--------------------------------------------------------------------------
  2. ;  SMOOTH * PC Magazine * Feb 14, 1989
  3. ;  Provides forward, backward and variable speed smooth scrolling
  4. ;  of a file to the display.  Requires Ega or Vga.
  5. ;  Syntax:  SMOOTH filespec
  6. ;--------------------------------------------------------------------------
  7. _TEXT          SEGMENT PUBLIC 'CODE'
  8.                ASSUME  CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
  9.                ORG     100H
  10. START:         JMP     MAIN
  11.  
  12. ;              DATA AREA
  13. ;              ---------
  14.                DB   CR,SPACE,SPACE,SPACE
  15.  
  16. COPYRIGHT      DB   CR,LF,"SMOOTH 1.0 (C) 1989 Ziff Communications Co."
  17. PROGRAMMER     DB   CR,LF,"PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
  18.  
  19.                DB   "Syntax:  SMOOTH filespec [/W][/Snn][Cmmm]",CR,LF
  20.                DB   "/W = Wordstar; /S = nn Speed; /C = mmm Color",CR,LF,LF
  21.                DB   "Use: ",24,25,", PgUp, PgDn, Home, End; Esc to Exit",CR,LF
  22.                DB   "+ = faster; - = slower; Space bar = pause; (0-9) = speed"
  23. COPY_LENGTH    EQU  $ - COPYRIGHT
  24.                DB   CR,LF,LF,"$",CTRL_Z
  25.  
  26. NOT_ENOUGH     DB      "Not enough memory$"
  27. NOT_EGA_VGA    DB      "Requires Ega/Vga$"
  28. NOT_FOUND      DB      "File not found$"
  29.  
  30. CR             EQU     13
  31. LF             EQU     10
  32. TAB            EQU     9
  33. CTRL_Z         EQU     26
  34. SPACE          EQU     32
  35. BOX            EQU     254
  36.  
  37. STATUS_REG     DW      3BAH
  38. VIDEO_SEGMENT  DW      0B000H
  39. INDEX_SEGMENT  DW      ?
  40. CRT_COLS       DW      ?
  41. CRT_LINE       DW      ?
  42. CRT_LEN        DW      ?
  43. CRT_START      DW      0
  44. CRT_END        DW      ?
  45. LAST_LINE      DW      ?
  46. STRIP_MASK     DB      0FFH
  47.  
  48. ATTRIBUTE      DB      07H
  49. DISPLAY_ROWS   DW      ?
  50. SCAN_LINESx2   DW      ?
  51.  
  52. UP             EQU     0
  53. DOWN           EQU     1
  54. DIRECTION      DB      UP
  55. CURRENT_SCANx2 DW      0
  56. SCAN_SPEED     DW      3
  57.  
  58. THIRTY_K       EQU     30 * 1024
  59. FILE_HANDLE    DW      ?
  60. FILE_END       DW      ?
  61. STORE_FLAG     DB      1
  62.  
  63. DISPATCH_KEY   DB      1, 48H, 50H, 49H, 51H, 47H, 4FH, 39H, 0DH, 0CH, 4EH, 4AH
  64. DISPATCH_CNT   EQU     $ - DISPATCH_KEY
  65.  
  66. DISPATCH_TABLE DW      EXIT,    UP_ARROW,  DOWN_ARROW,  PGUP, PGDN,  HOME
  67.                DW      END_KEY, SPACE_BAR, PLUS, MINUS, PLUS, MINUS
  68. DISPATCH_END   EQU     $ - 2
  69.  
  70. ;              CODE AREA
  71. ;              ---------
  72. MAIN           PROC    NEAR
  73.  
  74.                CLD                             ;All string operations forward.
  75.                MOV     BX,2000H                ;Allocate 128K of memory.
  76.                MOV     AH,4AH
  77.                INT     21H
  78.                MOV     DX,OFFSET NOT_ENOUGH    ;Exit with message if not enough.
  79.                JC      ERROR_MSG
  80.  
  81.                MOV     SP,0FFFEH               ;Stack to top of code segment.
  82.                MOV     AX,CS
  83.                ADD     AX,1000H                ;Use 2nd 64K for line indices.
  84.                MOV     INDEX_SEGMENT,AX
  85.                MOV     AX,40H                  ;Point to BIOS data area.
  86.                MOV     ES,AX
  87.  
  88.                MOV     AX,500H                 ;Make sure zero video page.
  89.                INT     10H
  90.                MOV     AX,1A00H                ;Get display info.
  91.                INT     10H
  92.                CMP     AL,1AH                  ;Function supported?
  93.                JNZ     CK_EGA                  ;If no, not VGA; check EGA.
  94.                CMP     BL,7                    ;Else, monochrome VGA?
  95.                JZ      GET_CRT_MODE            ;If yes, OK.
  96.                CMP     BL,8                    ;Else, color VGA?
  97.                JZ      GET_CRT_MODE            ;If yes, OK.
  98.  
  99. CK_EGA:        MOV     AH,12H
  100.                MOV     BL,10H                  ;Get EGA information.
  101.                INT     10H
  102.                MOV     DX,OFFSET NOT_EGA_VGA
  103.                CMP     BL,10H                  ;Is there an EGA?
  104.                JZ      ERROR_MSG               ;If no, exit with message.
  105.                TEST    ES:BYTE PTR [87H],8     ;Is EGA active?
  106.                JZ      GET_CRT_MODE            ;If yes, continue.
  107.  
  108. ERROR_MSG:     PUSH    DX                      ;Else, exit with message.
  109.                MOV     DX,OFFSET COPYRIGHT     ;Display copyright and syntax.
  110.                CALL    PRINT_STRING
  111.                POP     DX
  112.                CALL    PRINT_STRING
  113.                MOV     AL,1                    ;ERRORLEVEL = 1
  114.                JMP     TERMINATE               ;Exit.
  115.  
  116. GET_CRT_MODE:  MOV     BL,ES:[49H]             ;Retrieve CRT_MODE.
  117.                CMP     BL,7                    ;Is it mono?
  118.                JZ      GET_COLS                ;If yes, use defaults.
  119.                MOV     STATUS_REG,3DAH         ;Else, mono status register.
  120.                MOV     VIDEO_SEGMENT,0B800H    ;And mono video segment.
  121.  
  122.                CMP     BL,2                    ;Is mode BW80?
  123.                JZ      GET_COLS                ;If yes, defaults.
  124.                OR      BL,BL                   ;Is mode BW40?
  125.                JZ      GET_COLS                ;If yes, continue.
  126.                MOV     ATTRIBUTE,17H           ;Else, use color attribute.
  127.                CMP     BL,3                    ;Are we in CO80 or CO40?
  128.                JBE     GET_COLS                ;If yes, done here.
  129.                MOV     AX,3                    ;Else, change to CO80.
  130.                INT     10H
  131.  
  132. GET_COLS:      MOV     AX,ES:[4AH]             ;Retrieve CRT_COLS
  133.                MOV     CRT_COLS,AX             ; and save.
  134.                SHL     AX,1                    ;Double for attribute
  135.                MOV     CRT_LINE,AX             ; and save.
  136.  
  137.                PUSH    AX                      ;Save line length.
  138.                MOV     BH,2                    ;Get font information.
  139.                MOV     AX,1130H
  140.                INT     10H
  141.                SHL     CX,1                    ;Double scan lines/character.
  142.                MOV     SCAN_LINESx2,CX         ; and save.
  143.                INC     DL                      ;Adjust character rows.
  144.                XOR     DH,DH
  145.                MOV     DISPLAY_ROWS,DX         ;Store rows on screen.
  146.                POP     AX                      ;Retrieve screen width.
  147.                MUL     DL                      ; Times rows
  148.                MOV     CRT_LEN,AX              ; equals CRT length.
  149.  
  150. ;-------------------------------------------------------;
  151. ; Check for /W WordStar, /S speed or /C color switches. ;
  152. ;-------------------------------------------------------;
  153.                MOV     SI,81H                  ;Point to command line.
  154. NEXT_SWITCH:   LODSB                           ;Get a byte.
  155.                CMP     AL,CR                   ;Is it carriage return?
  156.                JZ      PARSE                   ;If yes, done here.
  157.                CMP     AL,"/"                  ;Is it switch delimiter?
  158.                JNZ     NEXT_SWITCH             ;If no, next byte.
  159.                MOV     BYTE PTR [SI-1],0       ;Else, ASCIIZ it out.
  160.                LODSB                           ;Get the switch character.
  161.                CMP     AL,CR                   ;Make sure it's not CR
  162.                JZ      PARSE                   ; so we don't go past end.
  163.                AND     AL,5FH                  ;Capitalize.
  164.                CMP     AL,"W"                  ;Is it "W"?
  165.                JNZ     CK_S                    ;If not, check "S".
  166.                MOV     STRIP_MASK,7FH          ;Else, we will strip high bit.
  167.  
  168. CK_S:          CMP     AL,"S"                  ;Is it "S"?
  169.                JNZ     CK_C                    ;If no, check "C".
  170.                CALL    DECIMAL_INPUT           ;Else, get speed request.
  171.                XOR     BH,BH
  172.                MOV     AX,SCAN_LINESx2
  173.                CMP     BX,AX                   ;If greater than maximum,
  174.                JBE     SAVE_SPEED
  175.                MOV     BX,AX                   ; use maximum, else use request.
  176. SAVE_SPEED:    MOV     SCAN_SPEED,BX
  177.                JMP     SHORT NEXT_SWITCH       ;Get next switch.
  178.  
  179. CK_C:          CMP     AL,"C"                  ;Is it "C"?
  180.                JNZ     NEXT_SWITCH             ;If no, next switch.
  181.                CALL    DECIMAL_INPUT           ;Else, get color request.
  182.                OR      BL,BL                   ;If black on black, skip.
  183.                JZ      NEXT_SWITCH
  184.                MOV     ATTRIBUTE,BL            ;Else, save color request.
  185.                JMP     NEXT_SWITCH             ;Next switch.
  186.  
  187. ;---------------------------------------;
  188. ; Parse the command line for filespec.  ;
  189. ;---------------------------------------;
  190. PARSE:         MOV     SI,81H                  ;Point to command line again.
  191. NEXT_PARSE:    LODSB                           ;Get a byte.
  192.                CMP     AL,SPACE                ;Parse off leading delimiters.
  193.                JA      LEADING_END
  194.                OR      AL,AL                   ;If ASCIIZ reached, done.
  195.                JNZ     NEXT_PARSE
  196. LEADING_END:   MOV     DX,SI
  197.                DEC     DX                      ;Adjust pointer.
  198.  
  199. FIND_END:      LODSB                           ;Find end of filespec.
  200.                CMP     AL,SPACE                ;If none white space, continue.
  201.                JAE     FIND_END
  202.                MOV     BYTE PTR [SI-1],0       ;ASCIIZ filespec.
  203.                MOV     AX,3D00H                ;Open file for reading.
  204.                INT     21H
  205.                MOV     DX,OFFSET NOT_FOUND     ;If fail, exit with message.
  206.                JNC     SAVE_HANDLE
  207.                JMP     ERROR_MSG
  208. SAVE_HANDLE:   MOV     FILE_HANDLE,AX          ;Else, save handle.
  209.                CALL    FIRST_READ              ;Read 30K.
  210.  
  211.                MOV     ES,VIDEO_SEGMENT        ;Clear the screen by writing
  212.                MOV     CX,CRT_LEN              ; the CRT length / 2 words
  213.                SHR     CX,1
  214.                XOR     DI,DI
  215.                MOV     AH,ATTRIBUTE            ; with spaces of attribute.
  216.                MOV     AL,SPACE
  217.                REP     STOSW
  218.  
  219.                MOV     BL,ATTRIBUTE            ;Add border with same attribute.
  220.                CALL    SET_BORDER
  221.  
  222.                MOV     DX,DISPLAY_ROWS         ;Place cursor in middle of row
  223.                XCHG    DH,DL                   ; of display.
  224.                SHR     DH,1
  225.                CALL    SET_CURSOR
  226.  
  227.                PUSH    SI                      ;Save file pointer.
  228.                MOV     SI,OFFSET COPYRIGHT     ;Display copyright and syntax
  229.                MOV     CX,COPY_LENGTH          ; with attribute.
  230. NEXT_COPY:     LODSB
  231.                MOV     AH,0EH
  232.                INT     10H
  233.                LOOP    NEXT_COPY
  234.                POP     SI                      ;Retrieve file pointer.
  235.  
  236.                XOR     BP,BP                   ;Use BP as line file pointer.
  237.                CALL    ADVANCE                 ;Write first line.
  238.                MOV     CRT_END,DI              ;Save CRT end.
  239.  
  240. ;*************** MAIN LOOP *****************;
  241. ; Poll the keyboard then scroll the screen. ;
  242. ;*******************************************;
  243. INPUT:         MOV     AH,1                    ;Is there a keystroke ready?
  244.                INT     16H
  245.                JZ      SCROLL_PAGE             ;If no, scroll the page.
  246.  
  247. GET_KEY:       XOR     AH,AH                   ;Else, get the keystroke.
  248.                INT     16H
  249.                SUB     AL,"0"                  ;If not number, check functions.
  250.                JC      FUNCTION
  251.                CMP     AL,9
  252.                JA      FUNCTION
  253.                XOR     AH,AH                   ;Else, change speed to number.
  254.                CALL    DO_SPEED
  255.                JMP     SHORT SCROLL_PAGE
  256.  
  257. FUNCTION:      PUSH    DI                      ;Save some registers.
  258.                PUSH    ES
  259.                PUSH    CS
  260.                POP     ES
  261.                MOV     AL,AH                   ;Scan code in AL.
  262.                MOV     DI,OFFSET DISPATCH_KEY  ;Check dispatch table.
  263.                MOV     CX,DISPATCH_CNT
  264.                REPNZ   SCASB
  265.                POP     ES                      ;Restore registers.
  266.                POP     DI
  267.                JNZ     INPUT                   ;Skip keystroke if no match.
  268.                SHL     CX,1                    ;Else, look up subroutine
  269.                MOV     BX,OFFSET DISPATCH_END
  270.                SUB     BX,CX
  271.                CALL    [BX]                    ; and process command.
  272. SCROLL_PAGE:   CALL    SCROLL                  ;Scroll the page.
  273.                JMP     SHORT INPUT             ;Next input.
  274.  
  275. ;---------------------------------------------------;
  276.  
  277. EXIT:          MOV     BX,FILE_HANDLE          ;Retrieve file handle
  278.                MOV     AH,3EH                  ; and close the file.
  279.                INT     21H
  280.  
  281.                MOV     BX,CRT_LINE
  282.                MOV     SI,CRT_START            ;Point to current visible page.
  283.                MOV     AX,SCAN_LINESx2         ;If current scan line is more
  284.                SHR     AX,1                    ; than half of character scan
  285.                CMP     CURRENT_SCANx2,AX       ; lines, move to next line.
  286.                JB      MOVE_PAGE
  287.                ADD     SI,BX
  288. MOVE_PAGE:     XOR     DI,DI
  289.                MOV     CX,CRT_LEN
  290.                SUB     CX,BX
  291.                SHR     CX,1
  292.                MOV     AH,ATTRIBUTE            ;Value to be used on last line.
  293.                XOR     AL,AL
  294.                PUSH    DS
  295.                MOV     DS,VIDEO_SEGMENT
  296.                REP     MOVSW                   ;Move the active page to page 0.
  297.                MOV     CX,BX
  298.                SHR     CX,1
  299.                REP     STOSW                   ;Clear the last line.
  300.                POP     DS
  301.  
  302.                XOR     BX,BX                   ;Return to a normal scan line of
  303.                XOR     CX,CX                   ; zero and an offset of zero.
  304.                CALL    SET_CRT
  305.                XOR     BL,BL                   ;Border back to black.
  306.                CALL    SET_BORDER
  307.                MOV     DX,DISPLAY_ROWS         ;Put cursor on bottom of screen.
  308.                XCHG    DH,DL
  309.                DEC     DH                      ;Up a line so screen won't scroll
  310.                DEC     DH                      ; with new DOS prompt.
  311.                CALL    SET_CURSOR
  312.                XOR     AL,AL                   ;ERRORLEVEL zero.
  313. TERMINATE:     MOV     AH,4CH                  ;Return to DOS.
  314.                INT     21H
  315.  
  316. MAIN           ENDP
  317.  
  318. ;            ***************
  319. ;            * SUBROUTINES *
  320. ;            ***************
  321. ;-----------------------------------------;
  322. ; What follows is the keyboard functions. ;
  323. ;-----------------------------------------;
  324. UP_ARROW:      CMP     DIRECTION,DOWN          ;Are we already scrolling down?
  325.                JZ      CK_SPEED                ;If yes, skip and go check speed.
  326.                CALL    CK_PAGE                 ;Else, is a full page displayed?
  327.                JBE     ARROW_END               ;If no, ignore.
  328.                INC     BX                      ;Else, move file pointer up
  329.                CALL    PAGE_UP                 ; display rows plus one.
  330.                MOV     DIRECTION,DOWN          ;Change scroll direction to down.
  331.                JMP     SHORT CK_SPEED          ;Check if speed is zero.
  332. ARROW_END:     RET
  333.  
  334. DOWN_ARROW:    CMP     DIRECTION,UP            ;Are we already scrolling up?
  335.                JZ      CK_SPEED                ;If yes, skip and go check speed.
  336.                CALL    MOVE_DOWN               ;Else, move file pointer to
  337.                MOV     DIRECTION,UP            ; bottom of page; direction down.
  338. CK_SPEED:      CMP     SCAN_SPEED,0            ;If scroll speed non-zero,
  339.                JNZ     ARROW_END               ; done, else increase by one.
  340.  
  341. PLUS:          MOV     AX,SCAN_SPEED           ;Increase scan speed by one
  342.                INC     AX                      ; scan line unless already
  343. DO_SPEED:      CMP     AX,SCAN_LINESx2         ; maximum speed.
  344.                JBE     STORE_SPEED
  345.                RET
  346.  
  347. MINUS:         MOV     AX,SCAN_SPEED           ;Decrease scan speed by one
  348.                DEC     AX                      ; scan line unless already
  349.                JS      MINUS_END               ; speed of zero (stationary).
  350. STORE_SPEED:   MOV     SCAN_SPEED,AX
  351. MINUS_END:     RET
  352.  
  353. PGUP:          CMP     DIRECTION,DOWN          ;Are we scrolling opposite of
  354.                JZ      REVERSE_UP              ; page request?  If yes, reverse.
  355.                CALL    CK_PAGE                 ;Else, is a full page displayed?
  356.                JBE     PGUP_END                ;If no, ignore.
  357.                INC     BX                      ;Else, move file pointer to top
  358.                CALL    PAGE_UP                 ; of page.
  359.                CALL    CK_PAGE                 ;Retrieve page length.
  360.                JA      DO_PAGE_UP              ;Can we page up a full page?
  361.                CALL    PARTIAL_PAGE            ;If no, partial page.
  362.                JZ      DO_WRITE                ;If already home, skip.
  363. DO_PAGE_UP:    CALL    PAGE_UP                 ;Else, move to top of prev. page.
  364. DO_WRITE:      CALL    WRITE_DOWN              ;Write the page. File pointer
  365.                JMP     SHORT PGUP_END          ; ends up back at bottom so done.
  366.  
  367. REVERSE_UP:    CALL    CK_PAGE                 ;If full page continue,
  368.                JAE     DO_REVERSE              ; else use partial page.
  369.                CALL    PARTIAL_PAGE
  370.                JZ      PGUP_END                ;If already home, ignore.
  371. DO_REVERSE:    MOV     SI,LAST_LINE            ;Else, retrieve last line.
  372.                CALL    PAGE_UP                 ;Move up a page.
  373.                CALL    WRITE_DOWN              ;Write that page.
  374.                CALL    MOVE_UP                 ;Move file pointer back to top.
  375. PGUP_END:      RET
  376.  
  377. PGDN:          CMP     DIRECTION,DOWN          ;Are we scrolling opposite of
  378.                JZ      REVERSE_DN              ; page request?  If yes, reverse.
  379.                CALL    NEW_PAGE                ;Else, move to next page.
  380.                RET
  381.  
  382. REVERSE_DN:    CALL    MOVE_DOWN               ;Else, move to bottom of page.
  383.                CALL    NEW_PAGE                ;Display next page.
  384.                CALL    MOVE_UP                 ;Move file pointer back to top.
  385. PGDN_END:      RET
  386.  
  387. HOME:          MOV     CURRENT_SCANx2,0        ;Move to scan line zero.
  388.                CMP     DIRECTION,DOWN          ;Are we scrolling opposite of
  389.                JZ      REVERSE_HOME            ; page request?  If yes, reverse.
  390.                CALL    CK_PAGE                 ;Is a full page displayed?
  391.                JA      GO_HOME                 ;If yes, continue, else ignore.
  392.                RET
  393.  
  394. REVERSE_HOME:  OR      BP,BP                   ;Are we already home?
  395.                JZ      HOME_END                ;If yes, ignore.
  396.                MOV     SI,LAST_LINE            ;Else, retrieve last line.
  397. GO_HOME:       MOV     BX,BP                   ;Move up the number of lines
  398.                SHR     BX,1                    ; currently displayed.
  399.                CALL    PAGE_UP
  400.                CALL    WRITE_DOWN              ;Write the first page.
  401. CK_REVERSE:    CMP     DIRECTION,DOWN          ;Scrolling down?
  402.                JNZ     HOME_END                ;If no, done.
  403.                CALL    MOVE_UP                 ;Else, move file pointer to top.
  404. HOME_END:      RET
  405.  
  406. END_KEY:       MOV     BX,0FFFFH               ;Move down until bottom reached.
  407.                CMP     DIRECTION,DOWN          ;Are we scrolling opposite of
  408.                JNZ     DO_END                  ; page request?  If yes, reverse.
  409.                MOV     SI,LAST_LINE            ;Retrieve last line.
  410. DO_END:        CALL    NO_WRITE                ;Top of last page and write.
  411.                JMP     SHORT CK_REVERSE        ;Check if file pointer correction
  412.  
  413. SPACE_BAR:     MOV     AH,1                    ;Wait until keystroke ready
  414.                INT     16H
  415.                JZ      SPACE_BAR
  416.                CMP     AL,SPACE                ;If space bar, eat keystroke.
  417.                JNZ     SPACE_END               ;Else, return to process.
  418.                XOR     AH,AH
  419.                INT     16H
  420. SPACE_END:     RET
  421.  
  422. ;-----------------------------;
  423. ; Function support routines.  ;
  424. ;-----------------------------;
  425. PARTIAL_PAGE:  MOV     CURRENT_SCANx2,0        ;Move to scan line zero.
  426.                MOV     BX,BP                   ;Return with number of lines
  427.                SHR     BX,1                    ; displayed.
  428.                OR      BX,BX                   ;Zero flag if already home.
  429.                RET
  430.  
  431. WRITE_DOWN:    CALL    CK_PAGE                 ;Write a full page plus one
  432.                INC     BX                      ; line to display.
  433.                MOV     STORE_FLAG,1
  434.                CALL    WRITE_PAGE
  435.                RET
  436.  
  437. MOVE_UP:       CALL    CK_PAGE                 ;Move up a full page plus one.
  438.                INC     BX
  439.                CALL    PAGE_UP
  440.                MOV     LAST_LINE,SI
  441.                RET
  442.  
  443. MOVE_DOWN:     CALL    CK_PAGE                 ;Move down a full page.
  444.                INC     BX
  445.                MOV     SI,LAST_LINE
  446.                MOV     STORE_FLAG,0
  447.                CALL    WRITE_PAGE
  448.                RET
  449.  
  450. NEW_PAGE:      CALL    CK_PAGE                 ;Get page size.
  451. NO_WRITE:      PUSH    BX                      ;Save.
  452.                MOV     STORE_FLAG,0            ;Move down the page request.
  453.                CALL    WRITE_PAGE
  454.                MOV     CX,BX                   ;Save lines moved.
  455.                CALL    CK_PAGE                 ;Get page size.
  456.                POP     AX                      ;Retrieve page request.
  457.                JBE     SHORT_PAGE              ;If short page, special.
  458.                INC     BX                      ;Else, move up page plus one.
  459.                CALL    PAGE_UP
  460.                CALL    WRITE_DOWN              ;And write the page.
  461.                CALL    CK_FILE_END
  462.                JNC     NEW_PAGE_END
  463.                MOV     AX,SCAN_LINESx2         ;Change scan line to last line.
  464.                DEC     AX
  465.                MOV     CURRENT_SCANx2,AX
  466.                RET
  467.  
  468. SHORT_PAGE:    MOV     BX,AX                   ;For short files, move back
  469.                SUB     BX,CX                   ; up the number of lines
  470.                JZ      NEW_PAGE_END            ; moved down.  Zero net result
  471.                CALL    PAGE_UP                 ; same as ignore.
  472. NEW_PAGE_END:  RET
  473.  
  474. ;------------------------------------------------------------;
  475. ; OUTPUT: BX = Display rows + 1; JBE set if not a full page  ;
  476. ;------------------------------------------------------------;
  477. CK_PAGE:       MOV     BX,DISPLAY_ROWS         ;Retrieve rows on screen.
  478.                SHL     BX,1                    ;Double for word index.
  479.                CMP     BP,BX                   ;Is there a full page?
  480.                PUSHF                           ;Preserve results.
  481.                SHR     BX,1                    ;Return BX = rows.
  482.                POPF                            ;Restore flags.
  483.                RET
  484.  
  485. ;------------------------------------------------;
  486. ; INPUT: BX = number of lines to move backward.  ;
  487. ;------------------------------------------------;
  488. PAGE_UP:       DEC     BP                      ;Index back one line.
  489.                DEC     BP                      ;It's a word index.
  490.                CALL    CK_BACKWARD             ;Move back one line.
  491.                DEC     BX                      ;Continue until requested lines.
  492.                JNZ     PAGE_UP
  493.                RET
  494.  
  495. ;----------------------------------------;
  496. ; INPUT: BX = Number of lines to write.  ;
  497. ;----------------------------------------;
  498. WRITE_PAGE:    MOV     DI,CRT_START            ;Point to CRT start.
  499. NEXT_WRITE:    CALL    CK_FILE_END             ;End of file?
  500.                JC      WRITE_END               ;If yes, done.
  501.                CALL    ADVANCE                 ;Else, write a line.
  502.                DEC     BX                      ;Continue until requested lines.
  503.                JNZ     NEXT_WRITE
  504. WRITE_END:     RET
  505.  
  506. ;******************************************;
  507. SCROLL:        MOV     AX,SCAN_LINESx2         ;Retrieve scan lines times two.
  508.                MOV     BX,CURRENT_SCANx2       ;Retrieve current scan line X 2.
  509.                CMP     DIRECTION,DOWN          ;Are we scrolling down?
  510.                JZ      SCROLL_DOWN             ;If yes scroll down.
  511.  
  512.                ADD     BX,SCAN_SPEED           ;Else, scroll up; add speed.
  513.                CMP     BX,AX                   ;Is it a wrap?
  514.                JB      SCROLL_IT               ;If no, display new scan line.
  515.                CALL    CK_FILE_END             ;Are we at end of file?
  516.                JNC     CK_CRT_UP               ;If no, continue
  517.                MOV     BX,AX                   ;Else, move to last scan line.
  518.                DEC     BX
  519.                JMP     SHORT SCROLL_IT
  520.  
  521. CK_CRT_UP:     SUB     BX,AX                   ;Subtract scan lines.
  522.                MOV     AX,CRT_LINE             ;Retrieve CRT line length.
  523.                ADD     CRT_START,AX            ;Move CRT start to next line.
  524.                CALL    CK_CRT_END              ;Check if end of video memory.
  525.                MOV     STORE_FLAG,1            ;Write a new line.
  526.                CALL    ADVANCE
  527.                MOV     CRT_END,DI              ;Save new CRT end.
  528.  
  529. SCROLL_IT:     MOV     CURRENT_SCANx2,BX       ;Store new scan line.
  530.                MOV     CX,CRT_START            ;Program registers to
  531.                CALL    SET_CRT                 ; new CRT start and scan line.
  532. SCROLL_END:    RET
  533.  
  534. SCROLL_DOWN:   SUB     BX,SCAN_SPEED           ;Scroll down; subtract speed.
  535.                JNC     SCROLL_IT               ;If not wrap, display new scan.
  536.                ADD     BX,AX                   ;Else, add scan lines.
  537.                OR      BP,BP                   ;Are we at home position?
  538.                JNZ     CK_CRT_DN               ;If no, continue.
  539.                XOR     BX,BX                   ;Else, set scan line to zero.
  540.                JMP     SHORT SCROLL_IT
  541.  
  542. CK_CRT_DN:     CALL    CK_CRT_START            ;Check if start of video memory.
  543.                MOV     SI,LAST_LINE            ;Retrieve last line.
  544.                DEC     BP                      ;Decrement file pointer
  545.                DEC     BP                      ; line start index.
  546.                CALL    CK_BACKWARD             ;Move file pointer up one line.
  547.                MOV     DI,CRT_START            ;Point to start of CRT.
  548.                MOV     STORE_FLAG,1            ;Write the line at top.
  549.                CALL    LINES
  550.                JMP     SHORT SCROLL_IT         ;Set new scan line.
  551.  
  552. ;------------------------------;
  553. ; Scroll support subroutines.  ;
  554. ;------------------------------;
  555. CK_CRT_START:  MOV     AX,CRT_LINE             ;Retrieve bytes in CRT line.
  556.                MOV     DI,CRT_START            ;Retrieve current CRT start.
  557.                OR      DI,DI                   ;Is it offset of zero?
  558.                JNZ     MOVE_CRT                ;If no, move down one line.
  559.  
  560.                PUSH    SI                      ;Else, save file pointer.
  561.                PUSH    DS                      ;Preserve data segment.
  562.                XOR     SI,SI                   ;Move page zero to top
  563.                MOV     DI,THIRTY_K             ; of video memory.
  564.                MOV     CX,CRT_LEN
  565.                SUB     DI,CX
  566.                MOV     CRT_START,DI
  567.                SHR     CX,1
  568.                MOV     DS,VIDEO_SEGMENT
  569.                REP     MOVSW
  570.                POP     DS                      ;Restore registers.
  571.                POP     SI
  572.                ADD     DI,AX                   ;Adjust for extra line.
  573.                MOV     CRT_END,DI              ;Store as new CRT end.
  574.  
  575. MOVE_CRT:      SUB     CRT_END,AX              ;Move CRT end up one line.
  576.                SUB     CRT_START,AX            ;Move CRT start up one line.
  577.                RET
  578.  
  579. ;---------------------------------;
  580. CK_CRT_END:    MOV     DI,CRT_END              ;Retrieve current CRT end.
  581.                CMP     DI,THIRTY_K             ;End of video memory?
  582.                JB      CK_END                  ;If no, done here.
  583.                PUSH    SI                      ;Else, save file pointer
  584.                PUSH    DS                      ; and data segment.
  585.                MOV     SI,CRT_START            ;Move page down to start
  586.                XOR     DI,DI                   ; of video memory.
  587.                MOV     CRT_START,DI
  588.                MOV     CX,CRT_LEN
  589.                SHR     CX,1
  590.                MOV     DS,VIDEO_SEGMENT
  591.                REP     MOVSW
  592.                POP     DS                      ;Restore registers.
  593.                POP     SI
  594. CK_END:        RET
  595.  
  596. ;---------------------------------;
  597. CK_BACKWARD:   CALL    GET_INDEX               ;Set file pointer to
  598.                SUB     SI,AX                   ; previous line.
  599.                CMP     SI,OFFSET FILE_BUFFER   ;Out of range of buffer?
  600.                JAE     BACKWARD_END            ;If no, done here.
  601.                PUSH    SI                      ;Else, preserve registers.
  602.                PUSH    BX
  603.                CALL    BACKWARD                ;Rearrange buffer and read
  604.                POP     BX                      ; in previous 30K of file.
  605.                POP     SI
  606.                ADD     SI,THIRTY_K             ;Adjust file pointer.
  607. BACKWARD_END:  MOV     LAST_LINE,SI            ;Save last line.
  608.                RET
  609.  
  610. ;-------------------------------------------------;
  611. ; OUTPUT: AX = length in bytes of previous line.  ;
  612. ;-------------------------------------------------;
  613. GET_INDEX:     PUSH    DS                      ;Preserve data segment.
  614.                MOV     DS,INDEX_SEGMENT        ;Second 64K is used for
  615.                MOV     AX,DS:[BP]              ; index of line length.
  616.                POP     DS
  617.                RET
  618.  
  619. ;-----------------------------------------------------------------------;
  620. ; INPUT: BX = Desired scan line times two; CX = Offset of video start.  ;
  621. ;-----------------------------------------------------------------------;
  622. SET_CRT:       MOV     DX,CS:STATUS_REG        ;Retrieve status register.
  623.                CLI                             ;No interrupts.
  624. HORIZONTAL:    IN      AL,DX                   ;Wait for horizontal trace
  625.                TEST    AL,8                    ; so will catch vertical
  626.                JZ      HORIZONTAL              ; retrace at start.
  627. VERTICAL:      IN      AL,DX                   ;Wait for vertical retrace.
  628.                RCR     AL,1
  629.                JC      VERTICAL
  630.                SUB     DX,6                    ;Point to CRT index register.
  631.  
  632.                MOV     AL,8                    ;Index to preset row scan.
  633.                OUT     DX,AL
  634.                INC     DX
  635.                SHR     BX,1                    ;Convert scan line times two
  636.                MOV     AL,BL                   ; to actual scan line (div 2).
  637.                OUT     DX,AL
  638.                DEC     DX                      ;Back to index register.
  639.  
  640.                MOV     BX,0D0CH                ;Set video offset.
  641.                CALL    SET_ADDRESS
  642.                DEC     DX                      ;Back to index register.
  643.                MOV     BX,0F0EH                ;Hide cursor by setting
  644.                MOV     CX,CRT_END              ; CRT end.
  645.                CALL    SET_ADDRESS
  646.                STI
  647.                RET                             ;Interrupts back on.
  648.  
  649. SET_ADDRESS:   SHR     CX,1                    ;Address has to be divided by 2.
  650.                MOV     AL,BL                   ;Most significant byte.
  651.                OUT     DX,AL
  652.                INC     DX
  653.                MOV     AL,CH                   ;Write it.
  654.                OUT     DX,AL
  655.                DEC     DX                      ;Next index.
  656.                MOV     AL,BH
  657.                OUT     DX,AL
  658.                INC     DX
  659.                MOV     AL,CL                   ;Least significant byte.
  660.                OUT     DX,AL                   ;Write it.
  661.                RET
  662.  
  663. ;---------------------------------------------------------------------------;
  664. ; A line is marked by either a carriage return or reaching the last column. ;
  665. ;---------------------------------------------------------------------------;
  666. ADVANCE:       XOR     DX,DX                   ;Use DX as counter.
  667.                CALL    LINES                   ;Write a line.
  668.                PUSH    DS
  669.                MOV     DS,INDEX_SEGMENT
  670.                MOV     DS:[BP],DX              ;Save length of line.
  671.                POP     DS
  672.                INC     BP                      ;Move to new index.
  673.                INC     BP
  674.                JNZ     ADVANCE_END             ;If 32K lines exceeded,
  675.                JMP     EXIT                    ; too much; give up.
  676. ADVANCE_END:   RET
  677.  
  678. ;---------------------------------;
  679. LINES:         MOV     CX,CRT_COLS             ;Retrieve columns.
  680.                MOV     LAST_LINE,SI            ;Save current line as new last.
  681. NEXT_LINES:    CMP     SI,FILE_END             ;End of buffer?; If no, continue.
  682.                JB      GET_LINES
  683.                CMP     FILE_END,OFFSET FILE_BUFFER + (THIRTY_K * 2)
  684.                JB      PAD_SPACES              ;If end of file, pad with spaces.
  685.                PUSH    BX                      ;If end of buffer, save
  686.                PUSH    CX                      ; our pointers and
  687.                PUSH    DX
  688.                PUSH    DI                      ; read next 30K.
  689.                CALL    FORWARD
  690.                POP     DI                      ;Restore pointers.
  691.                POP     DX
  692.                POP     CX
  693.                POP     BX
  694.  
  695. GET_LINES:     MOV     AH,ATTRIBUTE            ;Retrieve attribute.
  696.                LODSB                           ;Get a byte.
  697.                INC     DX                      ;Increment counter.
  698.                AND     AL,STRIP_MASK           ;Strip high bit for WordStar?
  699.                CMP     AL,CR                   ;Carriage return?
  700.                JZ      PAD_SPACES              ;If yes, pad balance of line.
  701.                CMP     AL,TAB                  ;Is it tab character?
  702.                JZ      DO_TAB                  ;If yes, tab.
  703.                CMP     AL,LF                   ;Is it linefeed?
  704.                JZ      NEXT_LINES              ;If yes, skip.
  705.                CMP     STORE_FLAG,1            ;Else, write to video memory?
  706.                JNZ     NEXT_BYTES              ;If no, next byte.
  707.                STOSW                           ;Else, store the byte/attribute.
  708. NEXT_BYTES:    LOOP    NEXT_LINES              ;Get next byte.
  709.                CMP     BYTE PTR [SI],CR        ;Adjust if next byte CR after
  710.                JNZ     END_LINES               ; complete line to avoid double
  711.                INC     SI                      ; spacing.
  712.                INC     DX
  713. END_LINES:     RET
  714.  
  715. DO_TAB:        PUSH    CX                      ;Save counter.
  716.                DEC     CX                      ;Adjust column counter.
  717.                AND     CX,7                    ;Get bottom three bits.
  718.                INC     CX                      ;Adjust.
  719.                PUSH    CX
  720.                CALL    PAD_SPACES              ;Move to next tab position.
  721.                POP     AX
  722.                POP     CX
  723.                SUB     CX,AX                   ;Adjust counter.
  724.                JNZ     NEXT_LINES              ;Next byte if last column.
  725.                RET
  726.  
  727. PAD_SPACES:    MOV     AL,SPACE                ;Space character.
  728. CK_DISPLAY:    CMP     STORE_FLAG,1            ;Are we to write it to screen?
  729.                JNZ     CK_DISP_END             ;If no, return.
  730. WRITE_VIEW:    REP     STOSW                   ;Else, write CX spaces/attribute.
  731. CK_DISP_END:   RET
  732.  
  733. ;-----------------------------------------------------; 
  734. ; OUTPUT: CY = 0 if not file end; CY = 1 if file end. ;
  735. ;-----------------------------------------------------;
  736. CK_FILE_END:   CMP     SI,FILE_END
  737.                JB      NOT_FILE_END
  738.                CMP     FILE_END,OFFSET FILE_BUFFER + (THIRTY_K * 2)
  739.                JAE     NOT_FILE_END
  740.                STC
  741.                RET
  742.  
  743. NOT_FILE_END:  CLC
  744.                RET
  745.  
  746. ;-------------------------------------------------------------------;
  747. ; These two subroutines read either the next or previous 30K bytes. ;
  748. ;-------------------------------------------------------------------;
  749. FORWARD:       XOR     CX,CX                   ;Zero in high half; Move file
  750.                MOV     DX,THIRTY_K             ; pointer forward 30K.
  751.                SUB     LAST_LINE,DX            ;Adjust last line 30K.
  752.                CALL    MOVE_POINTER
  753. FIRST_READ:    MOV     SI,OFFSET FILE_BUFFER + THIRTY_K
  754.                MOV     DI,OFFSET FILE_BUFFER   ;Move second half of buffer
  755.                CALL    MOVE_BUFFER             ; to first half and read 30K.
  756.                MOV     CX,-1                   ;Move file pointer back.
  757.                NEG     DX
  758.  
  759. MOVE_POINTER:  MOV     BX,FILE_HANDLE
  760.                MOV     AX,4201H                ;Move file pointer via DOS.
  761.                INT     21H
  762.                RET
  763.  
  764. BACKWARD:      MOV     CX,-1                   ;Move pointer back 30K.
  765.                MOV     DX,- (THIRTY_K * 2)
  766.                CALL    MOVE_POINTER
  767.                MOV     SI,OFFSET FILE_BUFFER              ;Move first half of
  768.                MOV     DI,OFFSET FILE_BUFFER + THIRTY_K   ; buffer to second.
  769.  
  770. MOVE_BUFFER:   PUSH    ES                      ;Preserve extra segment.
  771.                PUSH    CS
  772.                POP     ES
  773.                MOV     DX,SI                   ;Save file pointer.
  774.                MOV     CX,THIRTY_K / 2         ;Move 15K words (30K bytes).
  775.                REP     MOVSW
  776.                MOV     BX,FILE_HANDLE
  777.                MOV     CX,THIRTY_K             ;Read 30K.
  778.                MOV     AH,3FH
  779.                INT     21H
  780.                MOV     SI,DX                   ;Restore file pointer.
  781.                MOV     DX,AX
  782.                ADD     AX,OFFSET FILE_BUFFER + THIRTY_K
  783.                MOV     FILE_END,AX             ;Store end of buffer offset.
  784.                POP     ES
  785.                RET
  786.  
  787. ;--------------------------------------------------;
  788. ; INPUT:  SI points to parameter start.            ;
  789. ; OUTPUT: SI points to parameter end; BX = number. ;
  790. ;--------------------------------------------------;
  791. DECIMAL_INPUT: XOR     BL,BL                   ;Start with zero.
  792. NEXT_DECIMAL:  LODSB                           ;Get a character.
  793.                SUB     AL,"0"                  ;ASCII to binary.
  794.                JC      DECIMAL_END             ;If not between 0 and 9, skip.
  795.                CMP     AL,9
  796.                JA      DECIMAL_END
  797.                XCHG    AL,BL
  798.                MOV     CL,10                   ;Multiply current by 10 to
  799.                MUL     CL                      ; shift left one decimal.
  800.                ADD     BL,AL                   ;Add new number and store in BX.
  801.                JMP     SHORT NEXT_DECIMAL
  802. DECIMAL_END:   DEC     SI                      ;Adjust pointer.
  803.                RET
  804.  
  805. ;------------------------;
  806. ; INPUT: BL = Attribute. ;
  807. ;------------------------;
  808. SET_BORDER:    XOR     BH,BH
  809.                MOV     CL,4                    ;Use background attribute
  810.                SHR     BL,CL                   ; for border.
  811.                MOV     AH,0BH
  812.                INT     10H
  813.                RET
  814.  
  815. SET_CURSOR:    XOR     BH,BH
  816.                MOV     AH,2                    ;Set cursor position.
  817.                INT     10H
  818.                RET
  819.  
  820. PRINT_STRING:  MOV     AH,9
  821.                INT     21H
  822.                RET
  823.  
  824. FILE_BUFFER    =       $
  825.  
  826. _TEXT          ENDS
  827.                END     START
  828.